﻿/********************************************************
 *  ██████╗  ██████╗████████╗██╗
 * ██╔════╝ ██╔════╝╚══██╔══╝██║
 * ██║  ███╗██║        ██║   ██║
 * ██║   ██║██║        ██║   ██║
 * ╚██████╔╝╚██████╗   ██║   ███████╗
 *  ╚═════╝  ╚═════╝   ╚═╝   ╚══════╝
 * Geophysical Computational Tools & Library (GCTL)
 *
 * Copyright (c) 2023  Yi Zhang (yizhang-geo@zju.edu.cn)
 *
 * GCTL is distributed under a dual licensing scheme. You can redistribute 
 * it and/or modify it under the terms of the GNU Lesser General Public 
 * License as published by the Free Software Foundation, either version 2 
 * of the License, or (at your option) any later version. You should have 
 * received a copy of the GNU Lesser General Public License along with this 
 * program. If not, see <http://www.gnu.org/licenses/>.
 * 
 * If the terms and conditions of the LGPL v.2. would prevent you from using 
 * the GCTL, please consider the option to obtain a commercial license for a 
 * fee. These licenses are offered by the GCTL's original author. As a rule, 
 * licenses are provided "as-is", unlimited in time for a one time fee. Please 
 * send corresponding requests to: yizhang-geo@zju.edu.cn. Please do not forget 
 * to include some description of your company and the realm of its activities. 
 * Also add information on how to contact you by electronic and paper mail.
 ******************************************************/

#ifndef _GCTL_BASE_MESH_H
#define _GCTL_BASE_MESH_H

#include "list"

#include "meshdata.h"
#include "meshdata_int.h"
#include "meshdata_float.h"
#include "meshdata_double.h"
#include "meshdata_vector.h"
#include "meshdata_tensor.h"

#include "../geometry/vertex.h"
#include "../geometry/triangle2d.h"
#include "../geometry/tetrahedron.h"
#include "../io/gmsh_io.h"

namespace gctl
{
	enum mesh_type_e
	{
		REGULAR_MESH,
		LINEAR_MESH,
		TRI_TET_MESH,
		REGULAR_MESH_SPH,
		LINEAR_MESH_SPH,
		TRI_TET_MESH_SPH,
		REGULAR_GRID,
	};

	enum mesh_dim_e
	{
		MESH_2D,
		MESH_3D,
	};

	/**
	 * @brief      网格对象（纯虚类）。此类为所有具体网格类型的基类
	 */
	class base_mesh
	{
	public:
		base_mesh();
		virtual ~base_mesh();
		void clear();
		bool initiated() const;
		bool saved(std::string datname) const;
		meshdata *get_data(std::string datname) const;
		void get_all_data(array<meshdata*> &out_list) const;
		void *get_datval(std::string datname) const;
		void remove_data(std::string datname);
		void show_info(std::ostream &os = std::clog) const;
		void rename_data(std::string oldname, std::string newname);

		mesh_type_e get_meshtype() const;
		mesh_dim_e get_meshdim() const;
		int get_nodenum() const;
		int get_elenum() const;
		int get_datanum() const;

		std::string get_meshname() const;
		void set_meshname(std::string in_name);
		std::string get_meshinfo() const;
		void set_meshinfo(std::string in_info);

		meshdata *add_data(std::string in_name, mesh_data_type_e in_type, bool if_output, int init_val);
		meshdata *add_data(std::string in_name, mesh_data_type_e in_type, bool if_output, float init_val);
		meshdata *add_data(std::string in_name, mesh_data_type_e in_type, bool if_output, double init_val);
		meshdata *add_data(std::string in_name, mesh_data_type_e in_type, bool if_output, gctl::point3dc init_val);
		meshdata *add_data(std::string in_name, mesh_data_type_e in_type, bool if_output, gctl::tensor init_val);
		meshdata *add_data(std::string in_name, mesh_data_type_e in_type, bool if_output, mesh_data_value_e val_type);

		virtual void init(std::string in_name, std::string in_info, int xnum, int ynum, 
			double xmin, double ymin, double dx, double dy);
		virtual void init(std::string in_name, std::string in_info, int xbnum, int ybnum, int zbnum, 
			double xmin, double ymin, double zmin, double xsize, double ysize, double zsize);
		virtual void init(std::string in_name, std::string in_info, double lon_min, double lat_min, 
			double rad_min, double lon_size, double lat_size, double rad_size, int lon_bnum, int lat_bnum, int rad_bnum);
		virtual void init(std::string in_name, std::string in_info, double xmin, double ymin, 
			const gctl::array<double> &xsizes, const gctl::array<double> &ysizes);
		virtual void init(std::string in_name, std::string in_info, double xmin, double ymin, 
			double zmin, const gctl::array<double> &xsizes, const gctl::array<double> &ysizes, 
			const gctl::array<double> &zsizes);
		virtual void init(std::string in_name, std::string in_info, const gctl::array<gctl::vertex2dc> &in_nodes, 
			const gctl::array<gctl::triangle2d> &in_triangles);
		virtual void init(std::string in_name, std::string in_info, const gctl::array<gctl::vertex3dc> &in_nodes, 
			const gctl::array<gctl::tetrahedron> &in_tets);

		virtual void load_binary(std::string filename) = 0;
		virtual void save_binary(std::string filename) = 0;

		virtual void *get_node(unsigned int idx) = 0;
		virtual void *get_element(unsigned int idx) = 0;

		virtual void save_gmsh(std::string filename, index_packed_e packed = Packed);
		void save_gmsh(std::string filename, mesh_data_type_e d_type, output_type_e out_mode, index_packed_e packed = Packed);
		void save_gmsh(std::string filename, std::string datname, output_type_e out_mode, index_packed_e packed = Packed);

		/**
		 * @brief      将输入的自由点位上的浮点数据插值为规则网络的顶点或者块体数据
		 *
		 * @param      in_posi      输入的自由点位的坐标
		 * @param      in_val       输入的自由点位的数值
		 * @param[in]  search_xlen  插值搜索区域的x半径
		 * @param[in]  search_ylen  插值搜索区域的y半径
		 * @param[in]  search_deg   插值搜索区域的x半径绕x轴正方向逆时针旋转的角度（弧度）
		 * @param[in]  datname      网格后的数据名称
		 * @param[in]  d_type       网格后的数据类型
		 */
		virtual void load_data_cloud(const array<point2dc> &in_posi, const array<double> &in_val, double search_xlen, 
			double search_ylen, double search_deg, std::string datname, mesh_data_type_e d_type = NodeData);
		virtual void load_data_cloud(const array<point3dc> &in_posi, const array<double> &in_val, double search_xlen, 
			double search_ylen, double search_deg, std::string datname, mesh_data_type_e d_type = NodeData);

		virtual void extract_points(std::string datname, const array<point2dc> &in_posi, array<double> &out_val);
		virtual void extract_points(std::string datname, const array<point3dc> &in_posi, array<double> &out_val);
		virtual void extract_profile(std::string datname, const point2dc &start_p, const point2dc &end_p, int size_p, 
			array<point2dc> &out_posi, array<double> &out_val);
		virtual void extract_profile(std::string datname, const point3dc &start_p, const point3dc &end_p, int size_p, 
			double dh, array<point3dc> &out_posi, array<double> &out_val);

		virtual void edit_data(std::string datname, physical_type_e p_type, value_operator_e v_type, std::string para_str, int in_val);
		virtual void edit_data(std::string datname, physical_type_e p_type, value_operator_e v_type, std::string para_str, float in_val);
		virtual void edit_data(std::string datname, physical_type_e p_type, value_operator_e v_type, std::string para_str, double in_val);
		virtual void edit_data(std::string datname, physical_type_e p_type, value_operator_e v_type, std::string para_str, point3dc in_val);
		virtual void edit_data(std::string datname, physical_type_e p_type, value_operator_e v_type, std::string para_str, tensor in_val);

		virtual void purge_data(std::string datname, int in_val);
		virtual void purge_data(std::string datname, float in_val);
		virtual void purge_data(std::string datname, double in_val);
		virtual void purge_data(std::string datname, point3dc in_val);
		virtual void purge_data(std::string datname, tensor in_val);

	protected:
		mesh_type_e meshtype;
		mesh_dim_e  meshdim;
		std::string meshname;
		std::string meshinfo;

		int node_num, ele_num;
		bool initialized;

		std::list<meshdata*> saved_data;
		std::list<meshdata*>::iterator iter;

		/**
		 * 以下为类的私有函数 只能被类的公共函数调用
		 */

		void init(mesh_type_e in_type, mesh_dim_e in_dim, std::string in_name, std::string in_info);

		void load_headinfo(std::ifstream &infile, mesh_type_e expected_type, mesh_dim_e expected_dim);
		void load_datablock(std::ifstream &infile);
		void save_headinfo(std::ofstream &outfile);
		void save_datablock(std::ofstream &outfile);
	};
}

#endif //_GCTL_BASE_MESH_H